package dk.twu.analyzer.console;

import asg.cliche.Param;
import dk.twu.analyzer.console.model.DateElement;
import dk.twu.analyzer.console.model.ExchangeElement;
import dk.twu.analyzer.console.model.ITDRecordCollection;
import dk.twu.analyzer.loader.EODDataLoader;
import dk.twu.analyzer.loader.ITDDataLoader;
import dk.twu.analyzer.model.*;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Optional;

/**
 * Created by Tao Wu on 12/19/2014.
 */
public class Command {
    private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd");
    private final CommandStack commandStack;
    private final ExchangeList exchangeList;
    private final SymbolList symbolList;
    private final ITDDataLoader itdDataLoader;
    private final EODDataLoader eodDataLoader;


    public Command(ExchangeList exchangeList, SymbolList symbolList, ITDDataLoader itdDataLoader, EODDataLoader
            eodDataLoader) {
        commandStack = new CommandStack();
        this.exchangeList = exchangeList;
        this.symbolList = symbolList;
        this.itdDataLoader = itdDataLoader;
        this.eodDataLoader = eodDataLoader;
    }

    @asg.cliche.Command(description = "Date")
    public String date(String dateString) {
        DateElement date = new DateElement(LocalDate.parse(dateString, DATE_FORMATTER));
        commandStack.push(date);
        return date.getShortDescription();
    }

    @asg.cliche.Command(description = "Exchange")
    public String exchange(String exchangeCode) {
        Optional<Exchange> exchange = exchangeList.getExchange(exchangeCode);
        if (exchange.isPresent()) {
            ExchangeElement exchangeElement = new ExchangeElement(exchange.get());
            commandStack.push(exchangeElement);
            return exchangeElement.getShortDescription();
        } else {
            return "Invalid exchange code:" + exchangeCode;
        }
    }

    @asg.cliche.Command(description = "All exchanges")
    public String allExchange() {
        StringBuffer output = new StringBuffer();
        exchangeList.getExchangeMap().values().stream().forEach(ex -> output.append(ex.toString()).append("\n"));
        return output.toString();
    }

    @asg.cliche.Command(description = "Find symbols")
    public String findSymbol(@Param(name = "text", description = "Contain text") String text) {
        StringBuffer output = new StringBuffer();
        Collection<Symbol> symbols = symbolList.findSymbolNameContains(text);
        if (symbols != null && symbols.size() > 0)
            symbols.stream().forEach(symbol -> output.append(symbol.toString()).append("\n"));
        return output.toString();
    }

    @asg.cliche.Command(description = "Load intra-day data")
    public String itd(@Param(name = "exchange", description = "Exchange code") String exchange, @Param(name =
            "fromDate", description = "From date") String fromDate, @Param(name = "toDate", description = "To date")
    String toDate) {
        Exchange exchangeObj = exchangeList.getExchange(exchange).get();
        Collection<ITDRecord> recordCollection = new ArrayList<>();
        itdDataLoader.loadITDRecords(symbolList, Arrays.asList(exchangeObj), LocalDate.parse(fromDate,
                DATE_FORMATTER), LocalDate.parse(toDate, DATE_FORMATTER));
        ITDRecordCollection itdRecordCollection = new ITDRecordCollection(recordCollection);
        this.commandStack.push(itdRecordCollection);
        return "Loaded " + itdRecordCollection.size() + " intra-day records.";
    }

    @asg.cliche.Command(description = "Load end-of-day data")
    public String eod(@Param(name = "exchange", description = "Exchange code") String exchange, @Param(name =
            "fromDate", description = "From date") String fromDate, @Param(name = "toDate", description = "To date")
    String toDate) {
        Exchange exchangeObj = exchangeList.getExchange(exchange).get();
        Collection<EODRecord> eodRecords = eodDataLoader.loadEODRecords(symbolList, Arrays.asList(exchangeObj),
                LocalDate.parse(fromDate, DATE_FORMATTER), LocalDate.parse(toDate, DATE_FORMATTER));
        return "Loaded " + eodRecords.size() + " intra-day records.";
    }

    @asg.cliche.Command(description = "Show command Stack")
    public String showStack() {
        StringBuffer result = new StringBuffer();
        if (commandStack.size() == 0) {
            result.append("Stack is empty.");
        } else {
            result.append(commandStack.getDescription());
        }
        return result.toString();
    }

    @asg.cliche.Command(description = "Pop command Stack")
    public String popStack() {
        StringBuffer result = new StringBuffer();
        if (commandStack.size() == 0) {
            result.append("Stack is empty.");
        } else {
            String descFirst = commandStack.getTopElement().getShortDescription();
            commandStack.pop();
            result.append(descFirst + " is popped.");
        }
        return result.toString();
    }

    @asg.cliche.Command(description = "Clear command Stack")
    public String clearStack() {
        StringBuffer result = new StringBuffer();
        if (commandStack.size() == 0) {
            result.append("Stack is empty.");
        } else {
            commandStack.clear();
            result.append("Stack is cleared.");
        }
        return result.toString();
    }
}
